using BigPondUsage.Properties;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

namespace BigPondUsage
{
    /// <summary>
    /// An easy to use interface to access the BigPond usage meter. <br />
    /// ComVisible so it can be used in 3rd Party Applications.
    /// </summary>
    [ComVisible(true)]
    public class Usage
    {
        /// <summary>
        /// The Daily Usage HTML.
        /// </summary>
        private string dailyHtml = "";
        /// <summary>
        /// The My Usage HTML.
        /// </summary>
        private string myUsageHtml = "";
        /// <summary>
        /// The Monthly Usage HTML.
        /// </summary>
        private string monthlyHtml = "";
        /// <summary>
        /// The BrowseTo HTML.
        /// </summary>
        private string browseToHtml = "";

        /// <summary>
        /// The username of the account.
        /// </summary>
        private string username = "";
        /// <summary>
        /// The password of the account.
        /// </summary>
        private string password = "";
        /// <summary>
        /// The status of if DownloadUsage() or BrowseTo() has been completed after it has been called.
        /// </summary>
        private bool downloadStatus;
        /// <summary>
        /// This is holds a login for faster access to different pages (if the session hasn't expired). <br />
        /// Also used to setup the proxy server.
        /// </summary>
        private BigPondSMLogin login = null;

        /// <summary>
        /// Default constructor for Sidebar ActiveX
        /// </summary>
        public Usage() { }

        /// <summary>
        /// The default constructor for Usage. <br />
        /// Initialises a new instance of BigPondUsage.Usage to create an easy interface to gather BigPond usage details.
        /// </summary>
        /// <param name="userName">The username of the account. <br />Make sure to use the full e-mail address.</param>
        /// <param name="password">The password of the account.</param>
        public Usage(string userName, string password)
        {
            this.username = userName;
            this.password = password;
        }

        /// <summary>
        /// Sets an anonymous proxy to use.
        /// </summary>
        /// <param name="hostName">Hostname of the proxy server.</param>
        /// <param name="port">Port number of the proxy server.</param>
        public void SetProxy(string hostName, int port)
        {
            if (login == null)
                login = new BigPondSMLogin(this.username, this.password);
            login.useProxy = true;
            login.proxy = new WebProxy(hostName, port);
        }

        /// <summary>
        /// Sets a private proxy to use.
        /// </summary>
        /// <param name="hostName">Hostname of the proxy server.</param>
        /// <param name="port">Port number of the proxy server.</param>
        /// <param name="proxyUserName">Username for the proxy server.</param>
        /// <param name="proxyPassword">Password for the proxy server.</param>
        public void SetProxyWithAuth(string hostName, int port, string proxyUserName, string proxyPassword)
        {
            if (login == null)
                login = new BigPondSMLogin(this.username, this.password);
            login.useProxy = true;
            login.proxy = new WebProxy(hostName, port);
            login.proxy.Credentials = new NetworkCredential(proxyUserName, proxyPassword);
        }

        /// <summary>
        /// Disables the use of the proxy server.
        /// </summary>
        public void DisableProxy() {
            if (login == null)
                login = new BigPondSMLogin(this.username, this.password);
            login.proxy = null;
            login.useProxy = false;
        }

        /// <summary>
        /// Downloads and updates My Usage, Monthly Usage and Daily Usage pages with a new session.
        /// </summary>
        /// <exception cref="UsageDownloadException">If an error occurs while retrieving the usage page. <br />Can contain an Inner Exception with more details.</exception>
        public void DownloadUsage()
        {
            downloadStatus = false;
            if (login == null)
                login = new BigPondSMLogin(username, password);
            try
            {
                string[] pages = new string[3];
                pages = login.getPages();

                myUsageHtml = pages[0];
                monthlyHtml = pages[1];
                dailyHtml = pages[2];

                if (Utils.substring(myUsageHtml, "<title>", "</title>") == "LOG INTO BIGPOND")
                    throw new UserNamePasswordException(Resources.ResourceManager.GetString("UserNamePasswordExceptionString1"));

                if (Utils.substring(myUsageHtml, "<title>", "</title>") == "Telstra BigPond")
                    throw new UserNamePasswordException(Resources.ResourceManager.GetString("UserNamePasswordExceptionString1"));

            }
            catch (Exception ex)
            {
                throw new UsageDownloadException(Resources.ResourceManager.GetString("UsageDownloadExceptionString1") + ex.Message, ex);
            }

            // --------------
            //Force Pages
            //myUsageHtml = System.IO.File.ReadAllText(@"C:\Documents and Settings\Administrator\Desktop\fail\myusage-html.html");
            //monthlyHtml = System.IO.File.ReadAllText(@"C:\Documents and Settings\Administrator\Desktop\fail\history-monthly-html.html");
            //dailyHtml = System.IO.File.ReadAllText(@"C:\Documents and Settings\Administrator\Desktop\fail\history-daily-html.html");

            // --------------

            downloadStatus = true;
        }

        /// <summary>
        /// Calls DownloadUsage in a new Thread so the sidebar does not lock up when retrieving the usage details.
        /// </summary>
        public void DownloadUsageSidebar()
        {
            Thread runTestThread = new Thread(new ThreadStart(this.SideBarDownload));
            runTestThread.Name = "BigPondUsage DownloadUsage()";
            runTestThread.Start();
        }

        /// <summary>
        /// A DownloadUsage for the Windows Sidebar that catches all errors.
        /// </summary>
        private void SideBarDownload()
        {
            downloadStatus = false;
            if (login == null)
                login = new BigPondSMLogin(username, password);
            try
            {
                string[] pages = new string[3];
                pages = login.getPages();

                myUsageHtml = pages[0];
                monthlyHtml = pages[1];
                dailyHtml = pages[2];

                if (Utils.substring(myUsageHtml, "<title>", "</title>") == "LOG INTO BIGPOND")
                    throw new UserNamePasswordException(Resources.ResourceManager.GetString("UserNamePasswordExceptionString1"));

                if (Utils.substring(myUsageHtml, "<title>", "</title>") == "Telstra BigPond")
                    throw new UserNamePasswordException(Resources.ResourceManager.GetString("UserNamePasswordExceptionString1"));

                downloadStatus = true;
            }
            catch (UserNamePasswordException) { }
            catch (UsageDownloadException) { }
            catch (WebException) { }
        }

        /// <summary>
        /// Browses to another page using the same session. <br />
        /// WARNING: If the session has timed out an attempt to relogin will occur and the page will try to be downloaded. <br />
        /// The URL can be passed as "myusage", "monthly", "daily" or a full URL to a daily period. <br />Each will be put in their appropriate HTML variable. <br />
        /// If the site is non-standard it is dumped in browseToHtml.
        /// </summary>
        /// <param name="url">The URL to browse to using the same session. Can be "myusage", "monthly", "daily" or a direct URL to a daily period.</param>
        /// <exception cref="UsageDownloadException">If an error occurs while retrieving the usage page. <br />Can contain an Inner Exception with more details.</exception>
        public void BrowseToPage(string url)
        {
            if (url == "myusage")
                BrowseToPage(new Uri("https://my.bigpond.com/mybigpond/myaccount/myusage/default.do"));
            else if (url == "monthly")
                BrowseToPage(new Uri("https://my.bigpond.com/mybigpond/myaccount/myusage/monthly/default.do"));
            else if (url == "daily")
                BrowseToPage(new Uri("https://my.bigpond.com/mybigpond/myaccount/myusage/daily/default.do"));
            else
                BrowseToPage(new Uri(url));
        }

        /// <summary>
        /// Browses to another page using the same session. <br />
        /// WARNING: If the session has timed out an attempt to relogin will occur and the page will try to be downloaded.
        /// </summary>
        /// <param name="url">The URL to browse to using the same session.</param>
        /// <exception cref="UsageDownloadException">If an error occurs while retrieving the usage page. <br />Can contain an Inner Exception with more details.</exception>
        private void BrowseToPage(Uri url)
        {
            downloadStatus = false;
            if (login == null)
                login = new BigPondSMLogin(username, password);

            try
            {
                if (Utils.substring(url.AbsoluteUri, "", ".do") == "https://my.bigpond.com/mybigpond/myaccount/myusage/daily/default")
                    this.dailyHtml = login.browseTo(url.AbsoluteUri);
                if (url.AbsoluteUri == BigPondSMLogin.monthlyURL)
                    this.monthlyHtml = login.browseTo(url.AbsoluteUri);
                if (url.AbsoluteUri == BigPondSMLogin.myUsageURL)
                    this.myUsageHtml = login.browseTo(url.AbsoluteUri);
                else
                    this.browseToHtml = login.browseTo(url.AbsoluteUri);

                if (Utils.substring(this.browseToHtml, "<title>", "</title>") == "LOG INTO BIGPOND")
                    throw new UserNamePasswordException(Resources.ResourceManager.GetString("UserNamePasswordExceptionString1"));

                if (Utils.substring(myUsageHtml, "<title>", "</title>") == "Telstra BigPond")
                    throw new UserNamePasswordException(Resources.ResourceManager.GetString("UserNamePasswordExceptionString1"));
            }
            catch (Exception ex)
            {
                throw new UsageDownloadException(Resources.ResourceManager.GetString("UsageDownloadExceptionString1") + ex.Message, ex);
            }

            downloadStatus = true;
            
        }

        /// <summary>
        /// The HTML of the usage pages stored (for debug purposes). <br /> 
        /// Returns a string array of: 0-My Usage, 1-Monthly Usage, 2-Daily Usage, 3-Browse To<br />For debug purposes. <br />Read-only.
        /// </summary>
        /// <returns>A string array of the HTML for different usage pages.</returns>
        public string[] GetHtml()
        {
            string[] pages = new string[4];
            pages[0] = myUsageHtml;
            pages[1] = monthlyHtml;
            pages[2] = dailyHtml;
            pages[3] = browseToHtml;
            return pages;
        }

        /// <summary>
        /// The username of the account.
        /// </summary>
        public string UserName
        {
            get { return username; }
            set { this.username = value; }
        }

        /// <summary>
        /// The password of the account.
        /// </summary>
        public string Password
        {
            get { return password; }
            set { this.password = value; }
        }

        /// <summary>
        /// The status of whether or not DownloadUsage() or BrowseTo() has been completed successfully after it has been called. <br />Read-only.
        /// </summary>
        public bool DownloadStatus
        {
            get { return downloadStatus; }
        }

        /// <summary>
        /// The BigPond Account Number of the account. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageDownloadException">If the property is accessed and the usage has not been downloaded.</exception>
        public string AccountNumber
        {
            get
            {
                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                else
                    return Utils.substring(myUsageHtml, "<td width=\"60%\">", "</td>");
            }
        }

        /// <summary>
        /// The Current Plan of the account. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public string Plan
        {
            get
            {
                string planStr = "";
                try
                {
                    if (!downloadStatus)
                        throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                    else
                        planStr = Utils.substringArray(myUsageHtml, "<td width=\"40%\" valign=\"top\" nowrap=\"nowrap\">", "</td>")[0];
                }
                catch (ArgumentOutOfRangeException) { }

                return planStr;
            }
        }

        /// <summary>
        /// Returns true if it is a timed plan, else usage plan. <br />Read-only.
        /// </summary>
        public bool TimedPlan
        {
            get
            {
                bool timed = false;

                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                else
                {
                    if (UsageAllowanceDescription.Contains("hours per month"))
                        timed = true;

                        return timed;
                }
            }
        }

        /// <summary>
        /// Returns true if it is a Wireless G plan false if not. <br />Read-only.
        /// </summary>
        public bool WirelessGPlan
        {
            get
            {
                bool wireless = false;

                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                else
                {
                    if (Plan.Contains("Wireless Super G"))
                        wireless = true;
                    else if (Plan.Contains("Wireless G"))
                        wireless = true;
                    else
                        wireless = false;

                    return wireless;
                }
            }
        }

        /// <summary>
        /// The Usage Allowance Description. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public string UsageAllowanceDescription
        {
            get
            {
                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                else
                    return Utils.substring(myUsageHtml, "<td valign=\"top\" colspan=\"2\" nowrap=\"nowrap\">", "</td>");
            }
        }

        /// <summary>
        /// The Usage Allowance (in MB or Seconds). <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public double UsageAllowance
        {
            get
            {
                double usageAllowanceDbl = 0;
                try
                {
                    if (!downloadStatus)
                        throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                    else
                    {
                        if (!TimedPlan)
                        {
                            string allowanceStr = Utils.substring(myUsageHtml, "<td valign=\"top\" colspan=\"2\" nowrap=\"nowrap\">", "GB");
                            if (String.IsNullOrEmpty(allowanceStr))
                            {
                                allowanceStr = Utils.substring(myUsageHtml, "<td valign=\"top\" colspan=\"2\" nowrap=\"nowrap\">", "MB");
                                usageAllowanceDbl = Convert.ToDouble(allowanceStr, new NumberFormatInfo());
                            }
                            else
                            {
                                usageAllowanceDbl = Convert.ToDouble(allowanceStr, new NumberFormatInfo()) * 1000;
                            }
                        }
                        else
                        {
                            string allowanceStr = Utils.substring(myUsageHtml, "<td valign=\"top\" colspan=\"2\" nowrap=\"nowrap\">", " hour");
                            if (!String.IsNullOrEmpty(allowanceStr))
                            {
                                allowanceStr = Utils.substring(myUsageHtml, "<td valign=\"top\" colspan=\"2\" nowrap=\"nowrap\">", " hour");
                                usageAllowanceDbl = Convert.ToDouble(allowanceStr, new NumberFormatInfo()) * 3600;
                            }
                        }
                    }
                }
                catch (FormatException) { }

                return usageAllowanceDbl;
            }
        }

        /// <summary>
        /// The Monthly Plan Fee (in $). <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public double MonthlyPlanFee
        {
            get
            {
                double monthlyPlanFeeDbl = 0;
                try
                {
                    if (!downloadStatus)
                        throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                    else
                    {
                        string planFeeStr = Utils.substring(myUsageHtml, "<td width=\"40%\" valign=\"top\" nowrap=\"nowrap\">$", " monthly</td>");
                        monthlyPlanFeeDbl = Convert.ToDouble(planFeeStr, new NumberFormatInfo());
                    }
                }
                catch (FormatException) { }

                return monthlyPlanFeeDbl;
            }
        }

        /// <summary>
        /// The Monthly Plan Fee Period. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public string MonthlyPlanFeePeriod
        {
            get
            {
                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                else
                {
                    string monthlyPlanFeePeriodStr = "";
                    try
                    {
                        string monthlyPlanTypeStr = Utils.substring(myUsageHtml, "<td width=\"40%\" valign=\"top\" nowrap=\"nowrap\">$", "</td>");
                        string[] monthlyPlanTypeArry = monthlyPlanTypeStr.Split(new char[] { ' ' }, 2);
                        string temp = monthlyPlanTypeArry[1].Substring(0, 1);
                        monthlyPlanFeePeriodStr = temp.ToUpper(CultureInfo.CurrentCulture) + monthlyPlanTypeArry[1].Remove(0, 1);
                    }
                    catch (ArgumentOutOfRangeException) { }

                    return monthlyPlanFeePeriodStr;
                }

            }
        }

        /// <summary>
        /// The Account Holder's Name. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public string Accountholder
        {
            get
            {
                string accountholdernameStr = "";
                try
                {
                    if (!downloadStatus)
                        throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                    else
                    {
                        accountholdernameStr = Utils.substringArray(myUsageHtml, "<td width=\"100%\">", "</td>")[0];
                    }
                }
                catch (ArgumentOutOfRangeException) { }

                return accountholdernameStr;
            }
        }

        /// <summary>
        /// The Bill Period. <br />
        /// 0 - Start Date, 1 - End Date<br />
        /// Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public Collection<DateTime> BillPeriod
        {
            get
            {
                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                else
                {
                    Collection<DateTime> billPeriod = new Collection<DateTime>();
                    billPeriod.Add(BillPeriodStart);
                    billPeriod.Add(BillPeriodEnd);

                    return billPeriod;
                }
            }
        }

        /// <summary>
        /// The Bill Period as a String. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public string BillPeriodString
        {
            get
            {
                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                else
                {
                    return Utils.substring(myUsageHtml, "<td colspan=\"2\" style=\"vertical-align:bottom\">", "</td>");
                }
            }
        }

        /// <summary>
        /// The Billing Period Start Date. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public DateTime BillPeriodStart
        {
            get
            {
                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                else
                {
                    DateTime startDateTime = new DateTime();
                    try
                    {
                        string startDate = Utils.substring(myUsageHtml, "<td colspan=\"2\" style=\"vertical-align:bottom\">", " -");
                        startDateTime = Convert.ToDateTime(startDate, CultureInfo.CurrentCulture);
                    }
                    catch (FormatException) { }

                    return startDateTime;
                }
            }
        }

        /// <summary>
        /// The Billing Period End Date. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public DateTime BillPeriodEnd
        {
            get
            {
                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                else
                {
                    DateTime endDateTime = new DateTime();
                    try
                    {
                        string billPeriod = Utils.substring(myUsageHtml, "<td colspan=\"2\" style=\"vertical-align:bottom\">", "</td>");
                        string endDate = Utils.substring(billPeriod, " - ", "");
                        endDateTime = Convert.ToDateTime(endDate, CultureInfo.CurrentCulture);
                    }
                    catch (FormatException) { }

                    return endDateTime;
                }
            }
        }

        /// <summary>
        /// The current usage of the account (in MB or Seconds). <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public double CurrentUsage
        {
            get
            {
                double currentUsageDbl = 0;
                try
                {
                    if (!downloadStatus)
                        throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                    else
                    {
                        if (!TimedPlan)
                        {
                            string usageStr = Utils.substring(myUsageHtml, "<td colspan=\"2\" style=\"vertical-align:bottom\"><strong>", "MB</strong></td>");
                            usageStr = usageStr.Replace(",", "");
                            currentUsageDbl = Convert.ToDouble(usageStr, new NumberFormatInfo());
                        }
                        else
                        {
                            // Used less than hours this month
                            if (String.IsNullOrEmpty(Utils.substring(myUsageHtml, "<td colspan=\"2\" style=\"vertical-align:bottom\"><strong>", " Hour")))
                            {
                                // Used seconds this month
                                if (String.IsNullOrEmpty(Utils.substring(myUsageHtml, "<td colspan=\"2\" style=\"vertical-align:bottom\"><strong>", " Min")))
                                {
                                    string usageStr = Utils.substring(myUsageHtml, "<td colspan=\"2\" style=\"vertical-align:bottom\"><strong>", " Sec");
                                    usageStr = usageStr.Replace(":", "");
                                    currentUsageDbl = Convert.ToDouble(usageStr, new NumberFormatInfo());
                                }
                                // Used minutes this month
                                else
                                {
                                    string usageStr = Utils.substring(myUsageHtml, "<td colspan=\"2\" style=\"vertical-align:bottom\"><strong>", " Min");
                                    char[] split = new char[] { ':' };
                                    string[] usageStrSplit = usageStr.Split(split, 3);
                                    if (usageStrSplit.Length == 2)
                                    {
                                        double mins = Convert.ToDouble(usageStrSplit[0], new NumberFormatInfo());
                                        double secs = Convert.ToDouble(usageStrSplit[1], new NumberFormatInfo());
                                        currentUsageDbl = (mins * 60) + secs;
                                    }
                                    else
                                    {
                                        double mins = Convert.ToDouble(usageStrSplit[1], new NumberFormatInfo());
                                        double secs = Convert.ToDouble(usageStrSplit[2], new NumberFormatInfo());
                                        currentUsageDbl = (mins * 60) + secs;
                                    }
                                }
                            }
                            // Used hours this month
                            else
                            {
                                string usageStr = Utils.substring(myUsageHtml, "<td colspan=\"2\" style=\"vertical-align:bottom\"><strong>", " Hour");
                                char[] split = new char[] { ':' };
                                string[] usageStrSplit = usageStr.Split(split, 3);
                                double hours = Convert.ToDouble(usageStrSplit[0], new NumberFormatInfo());
                                double mins = Convert.ToDouble(usageStrSplit[1], new NumberFormatInfo());
                                double secs = Convert.ToDouble(usageStrSplit[2], new NumberFormatInfo());
                                currentUsageDbl = (hours * 60 * 60) + (mins * 60) + secs;
                            }
                        }
                    }
                }
                catch (FormatException) { }

                return currentUsageDbl;
            }
        }

        /// <summary>
        /// The current unrated usage of the account (in MB). Approximate.<br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public Double CurrentUnratedUsage
        {
            get
            {
                double currentUnratedDbl = 0;

                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));

                if (!TimedPlan)
                {
                    try
                    {
                        double scalePixels = Convert.ToDouble(Utils.substring(dailyHtml, "var scalePixels = ", ";"), new NumberFormatInfo());
                        double scaleMegabytes = Convert.ToDouble(Utils.substring(dailyHtml, "var scaleMegabytes = ", ";"), new NumberFormatInfo());
                        Collection<string> unratedWidthsStr = Utils.substringArray(dailyHtml, "<img src=\"/res/images/bar_unrated.gif\" height=\"14\" width=\"", "\" alt=\"Unrated usage\"");
                        unratedWidthsStr.RemoveAt(0);

                        if (unratedWidthsStr.Count > 0)
                        {
                            double[] unratedWidths = new double[unratedWidthsStr.Count];
                            for (int i = 0; i < unratedWidthsStr.Count; i++)
                            {
                                unratedWidths[i] = Convert.ToDouble(unratedWidthsStr[i], new NumberFormatInfo());
                            }

                            for (int i = 0; i < unratedWidths.Length; i++)
                            {
                                double approx = (unratedWidths[i] / scalePixels) * scaleMegabytes;
                                approx = Math.Round(approx, 2);
                                currentUnratedDbl = currentUnratedDbl + approx;
                            }
                        }
                    }
                    catch (ArgumentOutOfRangeException) { }
                    catch (ArgumentNullException) { }
                    catch (FormatException) { }
                    catch (OverflowException) { }
                }
                else
                {
                    currentUnratedDbl = 0;
                }

                return currentUnratedDbl;
            }

        }

        /// <summary>
        /// The current downloaded usage of the account. <br />Timed accounts shows this month's Volume. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public double CurrentDownloadedUsage
        {
            get
            {
                double currentUsageDbl = 0;
                try
                {
                    if (!downloadStatus)
                        throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                    else
                    {
                        if (WirelessGPlan)
                        {
                            Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection monthlyUsageValues = MonthlyUsageHistory.Values;
                            Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection.Enumerator monthlyUsageEnum = monthlyUsageValues.GetEnumerator();
                            monthlyUsageEnum.MoveNext();
                            currentUsageDbl = monthlyUsageEnum.Current[1];

                            /* Old WirelessG - Now more consistent
                            Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection monthlyUsageValues = MonthlyUsageHistory.Values;
                            Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection.Enumerator monthlyUsageEnum = monthlyUsageValues.GetEnumerator();
                            for (int i = 0; i < MonthlyUsageHistory.Values.Count; i++)
                                monthlyUsageEnum.MoveNext();
                            currentUsageDbl = monthlyUsageEnum.Current[1];
                             */
                        }
                        else
                        {
                            Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection monthlyUsageValues = MonthlyUsageHistory.Values;
                            Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection.Enumerator monthlyUsageEnum = monthlyUsageValues.GetEnumerator();
                            monthlyUsageEnum.MoveNext();
                            currentUsageDbl = monthlyUsageEnum.Current[1];
                        }
                    }
                }
                catch (FormatException) { }

                return currentUsageDbl;
            }
        }

        /// <summary>
        /// The current uploaded usage of the account. <br />Does not apply to Timed accounts. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public double CurrentUploadedUsage
        {
            get
            {
                double currentUsageDbl = 0;
                try
                {
                    if (!downloadStatus)
                        throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                    else
                    {
                        if (!TimedPlan)
                        {
                            if (WirelessGPlan)
                            {
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection monthlyUsageValues = MonthlyUsageHistory.Values;
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection.Enumerator monthlyUsageEnum = monthlyUsageValues.GetEnumerator();
                                monthlyUsageEnum.MoveNext();

                                currentUsageDbl = monthlyUsageEnum.Current[2];

                                /* Old WirelessG - Now more consistent
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection monthlyUsageValues = MonthlyUsageHistory.Values;
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection.Enumerator monthlyUsageEnum = monthlyUsageValues.GetEnumerator();
                                for (int i = 0; i < MonthlyUsageHistory.Values.Count; i++)
                                    monthlyUsageEnum.MoveNext();
                                currentUsageDbl = monthlyUsageEnum.Current[2];
                                 */
                            }
                            else
                            {
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection monthlyUsageValues = MonthlyUsageHistory.Values;
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection.Enumerator monthlyUsageEnum = monthlyUsageValues.GetEnumerator();
                                monthlyUsageEnum.MoveNext();

                                currentUsageDbl = monthlyUsageEnum.Current[2];
                            }
                        }
                        else
                        {
                            currentUsageDbl = 0;
                        }
                    }
                }
                catch (FormatException) { }

                return currentUsageDbl;
            }
        }

        /// <summary>
        /// The current usage over allowance of the account. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public double CurrentOverUsage
        {
            get
            {
                double currentUsageDbl = 0;
                try
                {
                    if (!downloadStatus)
                        throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                    else
                    {
                        if (!TimedPlan)
                        {
                            if (WirelessGPlan)
                            {
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection monthlyUsageValues = MonthlyUsageHistory.Values;
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection.Enumerator monthlyUsageEnum = monthlyUsageValues.GetEnumerator();
                                monthlyUsageEnum.MoveNext();

                                currentUsageDbl = monthlyUsageEnum.Current[4];

                                /* Old WirelessG - Now more consistent
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection monthlyUsageValues = MonthlyUsageHistory.Values;
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection.Enumerator monthlyUsageEnum = monthlyUsageValues.GetEnumerator();
                                for (int i = 0; i < MonthlyUsageHistory.Values.Count; i++)
                                    monthlyUsageEnum.MoveNext();
                                currentUsageDbl = monthlyUsageEnum.Current[4];
                                 */
                            }
                            else
                            {
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection monthlyUsageValues = MonthlyUsageHistory.Values;
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection.Enumerator monthlyUsageEnum = monthlyUsageValues.GetEnumerator();
                                monthlyUsageEnum.MoveNext();

                                currentUsageDbl = monthlyUsageEnum.Current[4];
                            }

                        }
                        else
                        {
                            Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection monthlyUsageValues = MonthlyUsageHistory.Values;
                            Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection.Enumerator monthlyUsageEnum = monthlyUsageValues.GetEnumerator();
                            monthlyUsageEnum.MoveNext();

                            currentUsageDbl = monthlyUsageEnum.Current[2];
                        }
                    }
                }
                catch (FormatException) { }

                return currentUsageDbl;
            }
        }

        /// <summary>
        /// The current free usage of the account.<br /> Does not apply to Timed accounts.<br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public double CurrentFreeUsage
        {
            get
            {
                double currentUsageDbl = 0;
                try
                {
                    if (!downloadStatus)
                        throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                    else
                    {
                        if (!TimedPlan)
                        {
                            if (WirelessGPlan)
                            {
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection monthlyUsageValues = MonthlyUsageHistory.Values;
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection.Enumerator monthlyUsageEnum = monthlyUsageValues.GetEnumerator();
                                monthlyUsageEnum.MoveNext();

                                currentUsageDbl = monthlyUsageEnum.Current[0];

                                /* Old WirelessG - Now more consistent
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection monthlyUsageValues = MonthlyUsageHistory.Values;
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection.Enumerator monthlyUsageEnum = monthlyUsageValues.GetEnumerator();
                                for (int i = 0; i < MonthlyUsageHistory.Values.Count; i++)
                                    monthlyUsageEnum.MoveNext();
                                currentUsageDbl = monthlyUsageEnum.Current[0];
                                 */
                            }
                            else
                            {
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection monthlyUsageValues = MonthlyUsageHistory.Values;
                                Dictionary<KeyValuePair<string[], DateTime>, double[]>.ValueCollection.Enumerator monthlyUsageEnum = monthlyUsageValues.GetEnumerator();
                                monthlyUsageEnum.MoveNext();

                                currentUsageDbl = monthlyUsageEnum.Current[0];
                            }
                        }
                    }
                }
                catch (FormatException) { }

                return currentUsageDbl;
            }
        }

        /// <summary>
        /// The usage delay status, as stated by BigPond. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public string UsageDelayStatus
        {
            get
            {
                string usageDelayStatusStr = "";
                try
                {
                    if (!downloadStatus)
                        throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                    else
                    {
                        usageDelayStatusStr = Utils.substringArray(myUsageHtml, "<td colspan=\"2\" style=\"vertical-align:bottom\">", "</td>")[3];
                    }
                }
                catch (ArgumentOutOfRangeException) { }

                return usageDelayStatusStr;
            }
        }

        /// <summary>
        /// The usage delay status, as stated by BigPond (as an Integer hour value). <br />Read-only.
        /// </summary>Bill
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public int UsageDelayValue
        {
            get
            {
                string usageDelayStatusStr = "";
                int usageDelayValue = 0;
                try
                {
                    if (!downloadStatus)
                        throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                    else
                    {
                        usageDelayStatusStr = Utils.substringArray(myUsageHtml, "<td colspan=\"2\" style=\"vertical-align:bottom\">", "</td>")[3];
                        usageDelayValue = Convert.ToInt32(String.Join(null, Regex.Split(usageDelayStatusStr, "[^\\d]")), CultureInfo.CurrentCulture);
                    }
                }
                catch (ArgumentOutOfRangeException) { }
                catch (ArgumentNullException) { }
                catch (FormatException) { usageDelayValue = 1; }
                catch (OverflowException) { }

                return usageDelayValue;
            }
        }

        /// <summary>
        /// Monthly usage history. <br />A dictionary that relates Bill Period (KeyValuePair string[] / DateTime) to Usage Values (double[]). <br />
        /// The KeyValuePair contains the string array and DateTime of the Bill Period. <br />
        /// The string array contains the Bill Period name and path to its daily usage page. <br />
        /// The string array order is: Bill Period Ending (0), Daily Usage Path (1) <br />
        /// The double array order is: <br />
        /// Usage Plan: Free Site Usage (0), Download Usage (1), Upload Usage (2), Total Usage (3), Usage Over Allowance (4) (In MB).<br />
        /// Timed Plan: Duration (0), Volume (1) (MB), Excess (2) (In Hours)<br />
        /// Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>

        // Using a KeyValuePair is really the easiest here as it is only one value.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public Dictionary<KeyValuePair<string[], DateTime>, double[]> MonthlyUsageHistory
        {
            get
            {
                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                if (!TimedPlan)
                {
                    monthlyHtml = monthlyHtml.Replace("style=\"color:ff0000;\" ", "");
                    Dictionary<KeyValuePair<string[], DateTime>, double[]> monthlyUsage = new Dictionary<KeyValuePair<string[], DateTime>, double[]>();

                    // A collection of all the different monthly usage period names.
                    Collection<string> periodNames = Utils.substringArray(monthlyHtml, "<a href=\"../daily/default.do", "</a></td>");
                    // A collection of all the other values to get. 0 - Free Site, 1 - Download Usage, 2 - Upload Usage, 3 - Total Usage, 4 - Usage Over Allowance.
                    // Last element of this collection is a dud collected by substring function, should be ignored.
                    Collection<string> values = Utils.substringArray(monthlyHtml, "<td align=\"right\">", "</td>");

                    if (WirelessGPlan)
                    {
                        // Hot fix for Super G plans - Different page layout
                        values = Utils.substringArray(monthlyHtml, "<td class=\"tdRight", "</td>");
                        // More hotfix for other Wireless G Plans
                        if (values.Count < 2)
                        {
                            values = Utils.substringArray(monthlyHtml, "<td align=\"right", "</td>");
                            values.RemoveAt(0);
                            values.RemoveAt(values.Count - 1);
                        }

                        for (int i = 0; i < values.Count; i++)
                        {
                            values[i] = values[i].Replace("Warn\">", "");
                            values[i] = values[i].Replace("\">", "");
                        }
                    }

                    int valuesCounter = 0;

                    for (int i = 0; i < periodNames.Count; i++)
                    {
                        string freeUsageStr = values[valuesCounter].Replace("&nbsp;&nbsp;&nbsp;", "").Replace("-", "0").Replace("<strong>", "").Replace("</strong>", "").Replace(",", "");
                        string downloadUsageStr = values[valuesCounter + 1].Replace("&nbsp;&nbsp;&nbsp;", "").Replace("-", "0").Replace("<strong>", "").Replace("</strong>", "").Replace(",", "");
                        string uploadUsageStr = values[valuesCounter + 2].Replace("&nbsp;&nbsp;&nbsp;", "").Replace("-", "0").Replace("<strong>", "").Replace("</strong>", "").Replace(",", "");
                        string totalUsageStr = values[valuesCounter + 3].Replace("&nbsp;&nbsp;&nbsp;", "").Replace("-", "0").Replace("<strong>", "").Replace("</strong>", "").Replace(",", "");
                        string usageOverStr = values[valuesCounter + 4].Replace("&nbsp;&nbsp;&nbsp;", "").Replace("-", "0").Replace("<strong>", "").Replace("</strong>", "").Replace(",", "");

                        double freeUsageDbl = 0;
                        double downloadUsageDbl = 0;
                        double uploadUsageDbl = 0;
                        double totalUsageDbl = 0;
                        double usageOverDbl = 0;

                        try
                        {
                            freeUsageDbl = Convert.ToDouble(freeUsageStr, new NumberFormatInfo());
                        }
                        catch (FormatException) { }
                        try
                        {
                            downloadUsageDbl = Convert.ToDouble(downloadUsageStr, new NumberFormatInfo());
                        }
                        catch (FormatException) { }

                        try
                        {
                            uploadUsageDbl = Convert.ToDouble(uploadUsageStr, new NumberFormatInfo());
                        }
                        catch (FormatException) { }

                        try
                        {
                            totalUsageDbl = Convert.ToDouble(totalUsageStr, new NumberFormatInfo());
                        }
                        catch (FormatException) { }

                        try
                        {
                            usageOverDbl = Convert.ToDouble(usageOverStr, new NumberFormatInfo());
                        }
                        catch (FormatException) { }

                        double[] valuesArray = new double[5];
                        // Different columns for Wireless G Plans
                        if (WirelessGPlan)
                        {
                            /*
                            valuesArray[0] = totalUsageDbl;
                            valuesArray[1] = freeUsageDbl;
                            valuesArray[2] = downloadUsageDbl;
                            valuesArray[3] = uploadUsageDbl; 
                            valuesArray[4] = usageOverDbl;
                             */
                            // Now same as normal account?
                            valuesArray[0] = freeUsageDbl;
                            valuesArray[1] = downloadUsageDbl;
                            valuesArray[2] = uploadUsageDbl;
                            valuesArray[3] = totalUsageDbl;
                            valuesArray[4] = usageOverDbl;

                        }
                        else
                        {
                            valuesArray[0] = freeUsageDbl;
                            valuesArray[1] = downloadUsageDbl;
                            valuesArray[2] = uploadUsageDbl;
                            valuesArray[3] = totalUsageDbl;
                            valuesArray[4] = usageOverDbl;
                        }

                        valuesCounter = valuesCounter + 5;

                        string[] periodArray = new string[2];
                        string periodName = periodNames[i].Split(new char[] { '>' })[1];
                        string pathToPeriod = periodNames[i].Split(new char[] { '"' })[0];
                        pathToPeriod = "https://my.bigpond.com/mybigpond/myaccount/myusage/daily/default.do" + pathToPeriod;

                        periodArray[0] = periodName;
                        periodArray[1] = pathToPeriod;

                        KeyValuePair<string[], DateTime> periodNamePair;
                        periodNamePair = new KeyValuePair<string[], DateTime>(periodArray, Convert.ToDateTime(periodArray[0], CultureInfo.CurrentCulture));

                        monthlyUsage.Add(periodNamePair, valuesArray);
                    }

                    return monthlyUsage;
                }
                else
                {
                    Dictionary<KeyValuePair<string[], DateTime>, double[]> monthlyUsage = new Dictionary<KeyValuePair<string[], DateTime>, double[]>();

                    // A collection of all the different monthly usage period names.
                    Collection<string> periodNames = Utils.substringArray(monthlyHtml, "<a href=\"../daily/default.do", "</a></td>");
                    // A collection of all the other values to get. 0 - Duration, 1 - Volume, 2 - Excess.
                    // Last element of this collection is a dud collected by substring function, should be ignored.
                    Collection<string> values = Utils.substringArray(monthlyHtml, "<td class=\"tdRightNoWrap\">", "</td>");

                    int valuesCounter = 0;

                    for (int i = 0; i < periodNames.Count; i++)
                    {
                        string duration = values[valuesCounter];
                        string volume = values[valuesCounter + 1];
                        string excess = values[valuesCounter + 2];

                        double durationDbl = 0;
                        double volumeDbl = 0;
                        double excessDbl = 0;

                        try
                        {
                            char[] separator = new char[] {','};
                            string[] durationSplit = duration.Split(separator, 4);
                            string daysSubStr = "";
                            string hoursSubStr = "";
                            string minsSubStr = "";
                            string secsSubStr = "";

                            if (durationSplit.Length == 3)
                            {
                                daysSubStr = "0";
                                hoursSubStr = String.Join(null, Regex.Split(durationSplit[0], "[^\\d]"));
                                minsSubStr = String.Join(null, Regex.Split(durationSplit[1], "[^\\d]"));
                                secsSubStr = String.Join(null, Regex.Split(durationSplit[2], "[^\\d]"));
                            }
                            else if (durationSplit.Length == 4)
                            {
                                daysSubStr = String.Join(null, Regex.Split(durationSplit[0], "[^\\d]"));
                                hoursSubStr = String.Join(null, Regex.Split(durationSplit[1], "[^\\d]"));
                                minsSubStr = String.Join(null, Regex.Split(durationSplit[2], "[^\\d]"));
                                secsSubStr = String.Join(null, Regex.Split(durationSplit[3], "[^\\d]"));
                            }

                            durationDbl = (Convert.ToDouble(daysSubStr, new NumberFormatInfo()) * 86400) + (Convert.ToDouble(hoursSubStr, new NumberFormatInfo()) * 3600) + (Convert.ToDouble(minsSubStr, new NumberFormatInfo()) * 60) + Convert.ToDouble(secsSubStr, new NumberFormatInfo());
                        }
                        catch (FormatException) { }
                        try
                        {
                            volume = volume.Replace(",", "");
                            volume = volume.Replace(" MB", "");
                            volumeDbl = Convert.ToDouble(volume, new NumberFormatInfo());
                        }
                        catch (FormatException) { }

                        try
                        {
                            char[] separator = new char[] { ',' };
                            string[] durationSplit = duration.Split(separator, 4);
                            string daysSubStr = "";
                            string hoursSubStr = "";
                            string minsSubStr = "";
                            string secsSubStr = "";

                            if (durationSplit.Length == 3)
                            {
                                daysSubStr = "0";
                                hoursSubStr = String.Join(null, Regex.Split(durationSplit[0], "[^\\d]"));
                                minsSubStr = String.Join(null, Regex.Split(durationSplit[1], "[^\\d]"));
                                secsSubStr = String.Join(null, Regex.Split(durationSplit[2], "[^\\d]"));
                            }
                            else if (durationSplit.Length == 4)
                            {
                                daysSubStr = String.Join(null, Regex.Split(durationSplit[0], "[^\\d]"));
                                hoursSubStr = String.Join(null, Regex.Split(durationSplit[1], "[^\\d]"));
                                minsSubStr = String.Join(null, Regex.Split(durationSplit[2], "[^\\d]"));
                                secsSubStr = String.Join(null, Regex.Split(durationSplit[3], "[^\\d]"));
                            }

                            durationDbl = (Convert.ToDouble(daysSubStr, new NumberFormatInfo()) * 86400) + (Convert.ToDouble(hoursSubStr, new NumberFormatInfo()) * 3600) + (Convert.ToDouble(minsSubStr, new NumberFormatInfo()) * 60) + Convert.ToDouble(secsSubStr, new NumberFormatInfo());
                        }
                        catch (FormatException) { }

                        double[] valuesArray = new double[3];
                        valuesArray[0] = durationDbl;
                        valuesArray[1] = volumeDbl;
                        valuesArray[2] = excessDbl;
                        valuesCounter = valuesCounter + 3;

                        string[] periodArray = new string[2];
                        string periodName = periodNames[i].Split(new char[] { '>' })[1];
                        string pathToPeriod = periodNames[i].Split(new char[] { '"' })[0];
                        pathToPeriod = "https://my.bigpond.com/mybigpond/myaccount/myusage/daily/default.do" + pathToPeriod;

                        periodArray[0] = periodName;
                        periodArray[1] = pathToPeriod;

                        KeyValuePair<string[], DateTime> periodNamePair;
                        periodNamePair = new KeyValuePair<string[], DateTime>(periodArray, Convert.ToDateTime(periodArray[0], CultureInfo.CurrentCulture));

                        monthlyUsage.Add(periodNamePair, valuesArray);
                    }

                    return monthlyUsage;
                }
                
            }
        }

        /// <summary>
        /// Daily usage history. <br />A dictionary that relates Day of Usage (string, DateTime) to Usage Values (double[]). <br />
        /// The double array order is: <br />
        /// Usage Plan: Download Usage (0), Upload Usage (1), Total Usage (2), Free Usage (3) (In MB).<br />
        /// Timed Plan: Duration (0) (Hours), Volume (1) (MB).<br />
        /// Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>

        // Using a KeyValuePair is really the easiest here as it is only one value.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public Dictionary<KeyValuePair<string, DateTime>, double[]> DailyUsageHistory
        {
            get
            {
                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));
                if (!TimedPlan)
                {
                    Dictionary<KeyValuePair<string, DateTime>, double[]> dailyUsage = new Dictionary<KeyValuePair<string, DateTime>, double[]>();

                    // A collection of all the different daily usage period names.
                    // The first value of periodNames is a dud collected by substring function, should be ignored.
                    Collection<string> periodNames = Utils.substringArray(dailyHtml, "<td nowrap=\"nowrap\">", "</td>");

                    // A collection of all the other values to get. 0 - Download Usage, 1 - Upload Usage, 3 - Total Usage, 4 - Free Usage.
                    // Last element of this collection is a dud collected by substring function, should be ignored.
                    Collection<string> values = Utils.substringArray(dailyHtml, "<td align=\"right\">", "</td>");

                    // Hot fix for Super G plans - Different page layout
                    if (WirelessGPlan)
                    {
                        values = Utils.substringArray(dailyHtml, "<td class=\"tdRight", "</td>");

                        // More hotfix for other Wireless G Plans
                        if (values.Count < 2)
                        {
                            values = Utils.substringArray(dailyHtml, "<td align=\"right", "</td>");
                            values.RemoveAt(0);
                            values.RemoveAt(values.Count - 1);
                        }

                        for (int i = 0; i < values.Count; i++)
                        {
                            values[i] = values[i].Replace("Warn\">", "");
                            values[i] = values[i].Replace("\">", "");
                        }
 
                        periodNames = Utils.substringArray(dailyHtml, "<td class=\"tdLeftNoWrap\">", "</td>");
                        // More hotfix for other Wireless G Plans
                        if (periodNames.Count < 2)
                        {
                            periodNames = Utils.substringArray(dailyHtml, " <td nowrap=\"nowrap\">", "</td>");
                            periodNames.Insert(0, "");
                        }
                    }

                    int valuesCounter = 0;

                    for (int i = 1; i < periodNames.Count; i++)
                    {
                        string downloadUsageStr = values[valuesCounter].Replace("&nbsp;&nbsp;&nbsp;", "").Replace("-", "0").Replace("<strong>", "").Replace("</strong>", "").Replace(",", "");
                        string uploadUsageStr = values[valuesCounter + 1].Replace("&nbsp;&nbsp;&nbsp;", "").Replace("-", "0").Replace("<strong>", "").Replace("</strong>", "").Replace(",", "");
                        string totalUsageStr = values[valuesCounter + 2].Replace("&nbsp;&nbsp;&nbsp;", "").Replace("-", "0").Replace("<strong>", "").Replace("</strong>", "").Replace(",", "");
                        string freeUsageStr = values[valuesCounter + 3].Replace("&nbsp;&nbsp;&nbsp;", "").Replace("-", "0").Replace("<strong>", "").Replace("</strong>", "").Replace(",", "");

                        double downloadUsageDbl = 0;
                        double uploadUsageDbl = 0;
                        double totalUsageDbl = 0;
                        double freeUsageDbl = 0;

                        try
                        {
                            downloadUsageDbl = Convert.ToDouble(downloadUsageStr, new NumberFormatInfo());
                        }
                        catch (FormatException) { }

                        try
                        {
                            uploadUsageDbl = Convert.ToDouble(uploadUsageStr, new NumberFormatInfo());
                        }
                        catch (FormatException) { }

                        try
                        {
                            totalUsageDbl = Convert.ToDouble(totalUsageStr, new NumberFormatInfo());
                        }
                        catch (FormatException) { }

                        try
                        {
                            freeUsageDbl = Convert.ToDouble(freeUsageStr, new NumberFormatInfo());
                        }
                        catch (FormatException) { }

                        double[] valuesArray = new double[4];
                        valuesArray[0] = downloadUsageDbl;
                        valuesArray[1] = uploadUsageDbl;
                        valuesArray[2] = totalUsageDbl;
                        valuesArray[3] = freeUsageDbl;

                        valuesCounter = valuesCounter + 4;

                        string periodName = periodNames[i].Replace("<strong>", "").Replace("</strong>", "");
                        KeyValuePair<string, DateTime> periodNamePair;
                        if (periodName == "Total")
                        {
                            periodNamePair = new KeyValuePair<string, DateTime>(periodName, new DateTime());
                        }
                        else
                        {
                            periodNamePair = new KeyValuePair<string, DateTime>(periodName, Convert.ToDateTime(periodName, CultureInfo.CurrentCulture));
                        }
                        dailyUsage.Add(periodNamePair, valuesArray);
                    }

                    return dailyUsage;
                }
                else
                {
                    Dictionary<KeyValuePair<string, DateTime>, double[]> dailyUsage = new Dictionary<KeyValuePair<string, DateTime>, double[]>();

                    // A collection of all the different monthly usage period names.
                    Collection<string> periodNames = Utils.substringArray(dailyHtml, "<a href=\"../detailed/default.do", "</a></td>");
                    // A collection of all the other values to get. 0 - Duration, 1 - Volume.
                    // Last element of this collection is a dud collected by substring function, should be ignored.
                    Collection<string> values = Utils.substringArray(dailyHtml, "<td class=\"tdRight\">", "</td>");

                    int valuesCounter = 0;

                    for (int i = 0; i < periodNames.Count; i++)
                    {
                        string duration = values[valuesCounter];
                        string volume = values[valuesCounter + 1];
 
                        double durationDbl = 0;
                        double volumeDbl = 0;

                        try
                        {
                            char[] separator = new char[] { ',' };
                            string[] durationSplit = duration.Split(separator, 4);
                            string daysSubStr = "";
                            string hoursSubStr = "";
                            string minsSubStr = "";
                            string secsSubStr = "";

                            if (durationSplit.Length == 3)
                            {
                                daysSubStr = "0";
                                hoursSubStr = String.Join(null, Regex.Split(durationSplit[0], "[^\\d]"));
                                minsSubStr = String.Join(null, Regex.Split(durationSplit[1], "[^\\d]"));
                                secsSubStr = String.Join(null, Regex.Split(durationSplit[2], "[^\\d]"));
                            }
                            else if (durationSplit.Length == 4)
                            {
                                daysSubStr = String.Join(null, Regex.Split(durationSplit[0], "[^\\d]"));
                                hoursSubStr = String.Join(null, Regex.Split(durationSplit[1], "[^\\d]"));
                                minsSubStr = String.Join(null, Regex.Split(durationSplit[2], "[^\\d]"));
                                secsSubStr = String.Join(null, Regex.Split(durationSplit[3], "[^\\d]"));
                            }

                            durationDbl = (Convert.ToDouble(daysSubStr, new NumberFormatInfo()) * 86400) + (Convert.ToDouble(hoursSubStr, new NumberFormatInfo()) * 3600) + (Convert.ToDouble(minsSubStr, new NumberFormatInfo()) * 60) + Convert.ToDouble(secsSubStr, new NumberFormatInfo());
                        }
                        catch (FormatException) { }
                        try
                        {
                            volume = volume.Replace(",", "");
                            volume = volume.Replace(" MB", "");
                            volumeDbl = Convert.ToDouble(volume, new NumberFormatInfo());
                        }
                        catch (FormatException) { }

                        double[] valuesArray = new double[2];
                        valuesArray[0] = durationDbl;
                        valuesArray[1] = volumeDbl;
                        valuesCounter = valuesCounter + 2;

                        string periodName = periodNames[i].Split(new char[] { '>' })[1];

                        KeyValuePair<string, DateTime> periodNamePair = new KeyValuePair<string, DateTime>(periodName, Convert.ToDateTime(periodName, CultureInfo.CurrentCulture));

                        dailyUsage.Add(periodNamePair, valuesArray);
                    }

                    return dailyUsage;
                }
            }
        }

        /// <summary>
        /// Details on when the account was shaped or unshaped. Direct text from BigPond. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public string ShapingDetailsText
        {
            get
            {
                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));

                string details = "";
                if (!WirelessGPlan)
                {
                    details = Utils.substring(dailyHtml, "</table><br />", "<h5>Usage Help</h5><br />");
                    details = details.Replace("<br /><br /><br />", "");
                    details = details.Replace("<br />", "\r\n");
                    details = details.Trim();
                }

                return details;
            }
        }

        /// <summary>
        /// Details on when the account was shaped or unshaped. <br />
        /// A dictionary that relates Day of Shaping (DateTime) to Status of Shaping (bool). True being Shaped and False being Unshaped. <br /><br />
        /// Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public Dictionary<DateTime, bool> ShapingDetails
        {
            get
            {
                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));

                Dictionary<DateTime, bool> shapingDetails = new Dictionary<DateTime, bool>();
                if (!WirelessGPlan)
                {
                    string details = Utils.substring(dailyHtml, "</table><br />", "<h5>Usage Help</h5><br />");
                    details = details.Replace("<br /><br /><br />", "");
                    details = details.Replace("<br />", "@");
                    details = details.Trim();



                    // Not shaped or unshaped this month
                    if (details != "@@")
                    {
                        string[] detailsSplit = details.Split('@');

                        foreach (string s in detailsSplit)
                        {
                            string date = Utils.substring(s, ", ", ".");
                            bool shaped = false;
                            if (s.Contains("Your usage was shaped"))
                                shaped = true;
                            else if (s.Contains("Your usage was unshaped"))
                                shaped = false;
                            try
                            {
                                shapingDetails.Add(Convert.ToDateTime(date, CultureInfo.CurrentCulture), shaped);
                            }
                            catch (FormatException) { }
                        }
                    }
                }
                return shapingDetails;
            }
        }

        /// <summary>
        /// Returns true if shaped, false if not. <br />Read-only.
        /// </summary>
        /// <exception cref="UsageNotDownloadedException">If the property is accessed and the usage has not been downloaded.</exception>
        public bool Shaped
        {
            get
            {
                if (!downloadStatus)
                    throw new UsageNotDownloadedException(Resources.ResourceManager.GetString("UsageDownloadExceptionString2"));

                bool shaped = false;

                if (String.IsNullOrEmpty(ShapingDetailsText))
                    shaped = false;
                else
                {
                    string shapedStr = ShapingDetailsText.Replace("Your usage was ", "|");
                    string[] shapedStrArr = shapedStr.Split('|');
                    if (shapedStrArr[shapedStrArr.Length - 1].Substring(0, 2) == "sh")
                        shaped = true;
                    else
                        shaped = false;
                }


                return shaped;
            }
        }


        /// <summary>
        /// Returns a System.String that represents the Usage object. <br />Prints out: Username, Password and the status of DownloadUsage().
        /// </summary>
        /// <returns>A System.String representation of BigPondUsage.Usage</returns>
        override public string ToString()
        {
            return this.GetType().ToString() +
                   "\r\nUsername: " + this.username +
                   "\r\nPassword: " + this.password +
                   "\r\nDownloadUsage() Status: " + this.downloadStatus.ToString();
        }

    }
}